package com.lingnan.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lingnan.dto.JobApplicationDto;
import com.lingnan.dto.JobApplicationQueryDTO;
import com.lingnan.dto.JobPostRecordQuery;
import com.lingnan.entity.dto.ResumeStatusRequest;
import com.lingnan.entity.po.*;
import com.lingnan.entity.vo.Result;
import com.lingnan.exception.MyException;
import com.lingnan.feign.InterviewFeignClient;
import com.lingnan.feign.NotificationFeignClient;
import com.lingnan.feign.UserFeignClient;
import com.lingnan.mapper.*;
import com.lingnan.service.JobApplicationService;
import com.lingnan.utils.LoginContextHolder;
import com.lingnan.vo.JobApplicationVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

/**
* @author abc20
* @description 针对表【job_application(职位投递记录表)】的数据库操作Service实现
* @createDate 2025-07-18 15:04:32
*/
@Service
@Slf4j
public class JobApplicationServiceImpl extends ServiceImpl<JobApplicationMapper, JobApplication>
    implements JobApplicationService {

    @Autowired
    private JobApplicationMapper jobApplicationMapper;

     @Autowired
     private InterviewFeignClient interviewFeignClient;

     @Autowired
     private NotificationFeignClient notificationFeignClient;

     @Autowired
     private UserFeignClient userFeignClient;

     @Autowired
     private JobSeekerMapper seekerMapper;

     @Autowired
     private JobPositionMapper jobPositionMapper;

    @Autowired
    private ResumeMapper resumeMapper;
    @Autowired
    private JobSeekerMapper jobSeekerMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private CompanyMapper companyMapper;

    @Autowired
    private InterviewMapper  interviewMapper;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean withdrawJobApplication(Long applicationId, Long seekerId) {
        // 1. 验证投递记录是否存在且属于当前用户
        JobApplication jobApplication = this.getById(applicationId);
        if (jobApplication == null) {
            log.warn("投递记录不存在，applicationId: {}", applicationId);
            return false;
        }

        if (!jobApplication.getSeekerId().equals(seekerId)) {
            log.warn("无权限操作此投递记录，applicationId: {}, seekerId: {}, recordSeekerId: {}",
                    applicationId, seekerId, jobApplication.getSeekerId());
            return false;
        }

        // 2. 检查投递状态，某些状态下可能不允许撤回
        if (jobApplication.getStatus() == 4) { // 已录用
            log.warn("已录用的投递记录不允许撤回，applicationId: {}", applicationId);
            MyException.cast("已录用的投递记录不允许撤回");
        }

        try {
            // 3. 删除相关的面试记录
            deleteRelatedInterviews(applicationId);

            // 4. 删除投递记录
            boolean deleteSuccess = this.removeById(applicationId);

            if (deleteSuccess) {
                log.info("投递记录撤回成功，applicationId: {}, seekerId: {}", applicationId, seekerId);
                return true;
            } else {
                log.error("删除投递记录失败，applicationId: {}", applicationId);
                return false;
            }

        } catch (Exception e) {
            log.error("撤回投递记录过程中发生异常，applicationId: {}", applicationId, e);
            MyException.cast("撤回投递记录失败：" + e.getMessage());
        }
        return true;
    }

    @Override
    public void createJobApplication(JobApplication jobApplication) {
        // 验证职位是否存在
        JobPosition position = jobPositionMapper.selectById(jobApplication.getPositionId());
        if (position == null) {
            MyException.cast("职位不存在");
        }

        // 检查是否重复投递
        LambdaQueryWrapper<JobApplication> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(JobApplication::getPositionId, jobApplication.getPositionId())
                .eq(JobApplication::getSeekerId, jobApplication.getSeekerId());

        if (this.count(wrapper) > 0) {
            MyException.cast("您已投递过该职位，请勿重复投递");
        }
        JobSeeker jobSeeker = seekerMapper.selectById(jobApplication.getSeekerId());
        this.save(jobApplication);
        //异步发送通知
        sendJobPositionNotification(position, jobSeeker);

    }

    @Async
    protected void sendJobPositionNotification(JobPosition position, JobSeeker jobSeeker) {
        String title="你有新的职位投递！";
        String content="【职位】:"+ position.getTitle()+"【求职者】:"+ jobSeeker.getRealName()+"【id】:"+ jobSeeker.getId();
        //没有发送者是系统通知，type为0表示系统通知
        notificationFeignClient.sendPersonalNotification(null, position.getHrId(),title,content,0);
    }

    @Override
    public IPage<JobApplicationVO> getApplicationsByHrId(Long hrId, Page<JobApplicationVO> page, JobApplicationQueryDTO queryDTO) {
        // 创建一个新的Page对象，泛型为JobApplication
        Page<JobApplication> applicationPage = new Page<>(page.getCurrent(), page.getSize());

        LambdaQueryWrapper<JobApplication> wrapper = new LambdaQueryWrapper<>();

        // 通过job_position表关联查询该HR的投递记录
        wrapper.inSql(JobApplication::getPositionId,
                "SELECT id FROM job_position WHERE hr_id = " + hrId);

        // 添加查询条件
        if (queryDTO.getStatus() != null) {
            wrapper.eq(JobApplication::getStatus, queryDTO.getStatus());
        }
        if (StringUtils.hasText(queryDTO.getPositionTitle())) {
            wrapper.inSql(JobApplication::getPositionId,
                    "SELECT id FROM job_position WHERE hr_id = " + hrId + " AND title LIKE '%" + queryDTO.getPositionTitle() + "%'");
        }
        if (queryDTO.getStartTime() != null) {
            wrapper.ge(JobApplication::getApplyTime, queryDTO.getStartTime());
        }
        if (queryDTO.getEndTime() != null) {
            wrapper.le(JobApplication::getApplyTime, queryDTO.getEndTime());
        }

        wrapper.orderByDesc(JobApplication::getApplyTime);

        IPage<JobApplication> result = this.page(applicationPage, wrapper);

        // 转换为VO并填充关联信息
        return result.convert(this::convertToVO);
    }

    @Override
    public IPage<JobApplicationVO> getApplicationsByPositionId(Long positionId, Page<JobApplicationVO> page, JobApplicationQueryDTO queryDTO) {
        // 验证职位归属
        JobPosition position = jobPositionMapper.selectById(positionId);
        if (position == null) {
            MyException.cast("职位不存在");
        }

        // 创建一个新的Page对象，泛型为JobApplication
        Page<JobApplication> applicationPage = new Page<>(page.getCurrent(), page.getSize());

        LambdaQueryWrapper<JobApplication> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(JobApplication::getPositionId, positionId);

        // 添加查询条件
        if (queryDTO.getStatus() != null) {
            wrapper.eq(JobApplication::getStatus, queryDTO.getStatus());
        }
        if (queryDTO.getStartTime() != null) {
            wrapper.ge(JobApplication::getApplyTime, queryDTO.getStartTime());
        }
        if (queryDTO.getEndTime() != null) {
            wrapper.le(JobApplication::getApplyTime, queryDTO.getEndTime());
        }

        wrapper.orderByDesc(JobApplication::getApplyTime);

        IPage<JobApplication> result = this.page(applicationPage, wrapper);
        return result.convert(this::convertToVO);
    }

    @Override
    public void updateApplicationStatus(Long applicationId, Integer status, Long hrId) {
        // 验证投递记录是否属于该HR
        JobApplication application = this.getById(applicationId);
        if (application == null) {
            MyException.cast("投递记录不存在");
            MyException.cast("投递记录不存在");
        }

        JobPosition position = jobPositionMapper.selectById(application.getPositionId());
        if (position == null || !position.getHrId().equals(hrId)) {
            MyException.cast("无权限操作该投递记录");
        }

        application.setStatus(Long.valueOf(status));
        this.updateById(application);

        log.info("HR {} 更新投递记录 {} 状态为 {}", hrId, applicationId, status);
    }

    @Override
    public void batchUpdateApplicationStatus(List<Long> applicationIds, Integer status, Long hrId) {
        if (applicationIds.isEmpty()) {
            MyException.cast("请选择要操作的记录");
        }

        // 验证所有记录都属于该HR
        List<JobApplication> applications = this.listByIds(applicationIds);
        List<Long> positionIds = applications.stream()
                .map(JobApplication::getPositionId)
                .collect(Collectors.toList());

        List<JobPosition> positions = jobPositionMapper.selectBatchIds(positionIds);
        boolean allBelongToHr = positions.stream()
                .allMatch(position -> position.getHrId().equals(hrId));

        if (!allBelongToHr) {
            MyException.cast("包含无权限操作的记录");
        }

        // 批量更新
        LambdaUpdateWrapper<JobApplication> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.in(JobApplication::getId, applicationIds)
                .set(JobApplication::getStatus, status);

        this.update(updateWrapper);

        log.info("HR {} 批量更新 {} 条投递记录状态为 {}", hrId, applicationIds.size(), status);
    }

    @Override
    public Map<String, Object> getApplicationStatistics(Long hrId) {
        Map<String, Object> statistics = new HashMap<>();

        // 总投递数
        LambdaQueryWrapper<JobApplication> totalWrapper = new LambdaQueryWrapper<>();
        totalWrapper.inSql(JobApplication::getPositionId,
                "SELECT id FROM job_position WHERE hr_id = " + hrId);
        long totalCount = this.count(totalWrapper);
        statistics.put("总数:totalCount", totalCount);

        // 各状态统计
        List<Map<String, Object>> statusCounts = baseMapper.countApplicationsByStatus(hrId);
        Map<Integer, Long> statusMap = statusCounts.stream()
                .collect(Collectors.toMap(
                        map -> (Integer) map.get("status"),
                        map -> (Long) map.get("count")
                ));

        statistics.put("待处理数:pendingCount", statusMap.getOrDefault(0, 0L));
        statistics.put("已查看数:viewedCount", statusMap.getOrDefault(1, 0L));
        statistics.put("面试中数:interviewCount", statusMap.getOrDefault(2, 0L));
        statistics.put("已拒绝数:rejectedCount", statusMap.getOrDefault(3, 0L));
        statistics.put("已录用数:hiredCount", statusMap.getOrDefault(4, 0L));

        // 今日新增投递
        LambdaQueryWrapper<JobApplication> todayWrapper = new LambdaQueryWrapper<>();
        todayWrapper.inSql(JobApplication::getPositionId,
                        "SELECT id FROM job_position WHERE hr_id = " + hrId)
                .ge(JobApplication::getApplyTime, LocalDate.now().atStartOfDay());
        long todayCount = this.count(todayWrapper);
        statistics.put("今日新增投递:todayCount", todayCount);

        return statistics;
    }



    @Override
    @Transactional
    public boolean deleteApplication(Long applicationId) {
        // 1. 检查是否有待面试的记录
        LambdaQueryWrapper<Interview> interviewWrapper = new LambdaQueryWrapper<>();
        interviewWrapper.eq(Interview::getApplicationId, applicationId)
                .eq(Interview::getStatus, 0); // 0:待面试

        List<Interview> pendingInterviews = interviewMapper.selectList(interviewWrapper);
        if (!pendingInterviews.isEmpty()) {
            throw new MyException("存在待面试记录，无法删除投递记录");
        }

        // 2. 删除已完成的面试记录（通过/拒绝）
        LambdaQueryWrapper<Interview> completedWrapper = new LambdaQueryWrapper<>();
        completedWrapper.eq(Interview::getApplicationId, applicationId)
                .in(Interview::getStatus, Arrays.asList(1, 2)); // 1:通过 2:未通过

        interviewMapper.delete(completedWrapper);

        // 3. 删除投递记录
        return this.removeById(applicationId);
    }

    private JobApplicationVO convertToVO(JobApplication application) {
        JobApplicationVO vo = new JobApplicationVO();
        BeanUtils.copyProperties(application, vo);
        vo.setStatus(application.getStatus().intValue());

        // 填充职位信息
        JobPosition position = jobPositionMapper.selectById(application.getPositionId());
        if (position != null) {
            vo.setPositionTitle(position.getTitle());

            // 查询公司名称 - 添加 null 检查
            Company company = companyMapper.selectById(position.getCompanyId());
            if (company != null) {
                vo.setCompanyName(company.getName());
            }
        }

        // 填充求职者信息 - 添加 null 检查
        JobSeeker seeker = jobSeekerMapper.selectById(application.getSeekerId());
        if (seeker != null) {
            vo.setSeekerName(seeker.getRealName());

            UserAccount user = userMapper.selectById(seeker.getUserId());
            if (user != null) {
                vo.setSeekerPhone(user.getPhone());
                vo.setSeekerEmail(user.getEmail());
            }
        }

        return vo;
    }



    /**
     * 删除相关的面试记录
     * @param applicationId 投递记录ID
     */
//    @GlobalTransactional
    private void deleteRelatedInterviews(Long applicationId) {
            try {
                Result<List<Interview>> interviewResult = interviewFeignClient.getInterviewsByApplicationId(applicationId);

                if (interviewResult.isSuccess() && interviewResult.getData() != null) {
                    List<Interview> interviews = interviewResult.getData();

                    // 检查是否有进行中的面试
                    boolean hasOngoingInterview = interviews.stream()
                        .anyMatch(interview -> interview.getStatus() == 0 &&
                                 interview.getInterviewTime().after(new Date()));

                    if (hasOngoingInterview) {
                        MyException.cast("存在未完成的面试安排，无法撤回投递");
                    }
                    log.info("准备删除面试记录");
                    // 调用远程服务删除面试记录
                    Result<Boolean> deleteResult = interviewFeignClient.deleteInterviewsByApplicationId(applicationId);

                    if (!deleteResult.isSuccess()) {
                        MyException.cast("删除面试记录失败：" + deleteResult.getMessage());
                    }
                }
            } catch (Exception e) {
                log.error("调用面试服务失败，applicationId: {}", applicationId, e);
                // 根据业务需求决定是否继续执行还是抛出异常
                // MyException.cast("调用面试服务失败，无法完成撤回操作");
            }
    }

    @Override
    public List<JobApplication> getJobApplicationById(Long id) {
        LambdaQueryWrapper<JobApplication> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(JobApplication::getSeekerId, id);
        return jobApplicationMapper.selectList(queryWrapper);
    }

    @Override
    public IPage<JobApplicationDto> getListByPage(int pageNum, int pageSize, JobPostRecordQuery query) {
        // 创建分页对象
        Page<JobApplicationDto> page = new Page<>(pageNum, pageSize);

        // 执行分页查询
        return jobApplicationMapper.selectJobApplicationPage(page, query);
    }


    @Override
    public void updateApplicationStatus(Long id, Long status) {
        // 状态值验证
        validateStatus(status);

        // 检查记录是否存在
        JobApplication application = jobApplicationMapper.selectById(id);
        if (application == null) {
            MyException.cast("投递记录不存在");
        }

        // 状态变更验证
        validateStatusTransition(application.getStatus(), status);

        // 更新状态
        JobApplication updateEntity = new JobApplication();
        updateEntity.setId(id);
        updateEntity.setStatus(status);

        int result = jobApplicationMapper.updateById(updateEntity);
        if (result == 0) {
            MyException.cast("更新投递状态失败");
        }

   // 发送通知给用户，异步
    sendNotificationAsync(application, status);

    }

    // 将通知逻辑提取到单独的方法中
    @Async
    protected void sendNotificationAsync(JobApplication application, Long status) {
        try {
            // 获取用户信息
            JobSeeker jobSeeker = seekerMapper.selectOne(new LambdaQueryWrapper<JobSeeker>()
                    .select(JobSeeker::getUserId)
                    .eq(JobSeeker::getId, application.getSeekerId()));

            if (jobSeeker == null) {
                throw new RuntimeException("未找到求职者信息");
            }

            Long receiverId = jobSeeker.getUserId();
            if (receiverId == null) {
                throw new RuntimeException("求职者用户ID为空");
            }

            // 根据hrId获取公司信息
            String loginId = LoginContextHolder.getLoginId();
            if (loginId == null || loginId.isEmpty()) {
                throw new RuntimeException("当前登录用户ID为空");
            }

            Long hrUserId;
            try {
                hrUserId = Long.valueOf(loginId);
            } catch (NumberFormatException e) {
                throw new RuntimeException("登录用户ID格式错误", e);
            }

            Company company;
            try {
                company = userFeignClient.getCompanyByHrUserId(hrUserId);
            } catch (Exception e) {
                throw new RuntimeException("获取公司信息失败", e);
            }

            if (company == null || company.getName() == null) {
                throw new RuntimeException("公司信息不完整");
            }
            String companyName = company.getName();

            // 职位信息
            JobPosition position = jobPositionMapper.selectOne(new LambdaQueryWrapper<JobPosition>()
                    .select(JobPosition::getTitle)
                    .eq(JobPosition::getId, application.getPositionId()));

            if (position == null || position.getTitle() == null) {
                throw new RuntimeException("职位信息不完整");
            }
            String jobName = position.getTitle();

            ResumeStatusRequest request = new ResumeStatusRequest();
            request.setReceiverId(receiverId);
            request.setCompanyName(companyName);
            request.setPosition(jobName);

            // 根据数字状态设置对应的字符串状态
            String statusStr;
            switch (status.intValue()) {
                case 1:
                    statusStr = "已查看";
                    break;
                case 2:
                    statusStr = "面试中";
                    break;
                case 3:
                    statusStr = "已拒绝";
                    break;
                case 4:
                    statusStr = "已录用";
                    break;
                default:
                    statusStr = "待处理";
                    break;
            }

            request.setStatus(statusStr);

            notificationFeignClient.sendResumeStatusNotification(request);
        } catch (Exception e) {
            log.error("异步发送通知失败，applicationId: {}", application.getId(), e);
            // 异步方法中的异常不会影响主流程，但需要记录日志
        }
    }
    @Override
    public void batchUpdateApplicationStatus(List<Long> ids, Long status) {
        if (ids == null || ids.isEmpty()) {
            MyException.cast("投递记录ID列表不能为空");
        }

        // 状态值验证
        validateStatus(status);

        // 批量更新
        LambdaUpdateWrapper<JobApplication> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.in(JobApplication::getId, ids)
                .set(JobApplication::getStatus, status);

        int result = jobApplicationMapper.update(null, updateWrapper);
        if (result == 0) {
            MyException.cast("批量更新投递状态失败");
        }
    }

    /**
     * 验证状态值是否有效
     */
    private void validateStatus(Long status) {
        if (status < 0 || status > 4) {
            MyException.cast("无效的状态值，状态值必须在0-4之间");
        }
    }

    /**
     * 验证状态转换是否合法
     */
    private void validateStatusTransition(Long currentStatus, Long newStatus) {
        // 根据业务规则验证状态转换
        // 例如：已录用(4)的不能再改为其他状态
//        if (currentStatus == 4 && !newStatus.equals(4)) {
//            MyException.cast("已录用的投递记录不能更改为其他状态");
//        }

        // 已拒绝(3)的不能改为面试中(2)
        if (currentStatus == 3 && newStatus == 2) {
            MyException.cast("已拒绝的投递记录不能更改为面试中");
        }
    }


}




